package com.grt192.mechanism.cannonbot;

import com.grt192.actuator.GRTSolenoid;
import com.grt192.actuator.GRTTwoWaySolenoid;
import com.grt192.core.Mechanism;
import com.grt192.event.component.SwitchListener;
import com.grt192.mechanism.GRTCompressor;
import com.grt192.sensor.GRTSwitch;

/**
 * Dual barrel cannon assembly, with a system for pressurizing one barrel while
 * the other is firing
 */
public class CBCannon extends Mechanism implements SwitchListener {
	// Constants
	public static final int SLEEP_TIME = 50;
	public static final int LEFT_BARREL = 0;
	public static final int RIGHT_BARREL = 1;
	public static final long TIMEOUT_LENGTH = 2000;
	// Parts
	private GRTTwoWaySolenoid tankSelectorSolenoid;
	private GRTSolenoid tankASolenoid;
	private GRTSolenoid tankBSolenoid;
	private GRTCompressor cannonCompressor;
	private GRTSwitch fireSwitch;

	// Properties

	private boolean firing;
	private boolean leftReady = false;
	private boolean rightReady = false;
	private int activeBarrel;
	private int inactiveBarrel;

	public CBCannon(int tasolpin, int tbsolpin, int tssolpin1, int tssolpin2,
			GRTCompressor compressor) {
		this(new GRTSolenoid(tasolpin), new GRTSolenoid(tbsolpin),
				new GRTTwoWaySolenoid(tssolpin1, tssolpin2),
				compressor);

	}

	public CBCannon(GRTSolenoid tankasol, GRTSolenoid tankbsol,
			GRTTwoWaySolenoid tankselecsol, GRTCompressor compressor) {
		this.leftReady = false;
		this.rightReady = false;
		this.activeBarrel = LEFT_BARREL;
		this.inactiveBarrel = RIGHT_BARREL;
		this.tankASolenoid = tankasol;
		tankASolenoid.start();

		this.tankBSolenoid = tankbsol;
		tankBSolenoid.start();

		this.tankSelectorSolenoid = tankselecsol;
		tankSelectorSolenoid.start();

		this.fireSwitch = new GRTSwitch(3, 9, "fireswitch");
		fireSwitch.start();

		this.cannonCompressor = compressor;
		if(!compressor.isStarted())
			cannonCompressor.startCompressor();
		addActuator("tankasol", tankASolenoid);
		addActuator("tankbsol", tankBSolenoid);
		addActuator("tankselecsol", tankSelectorSolenoid);
		addSensor("fireswitch", fireSwitch);
		// listen to the projectile switch
		fireSwitch.addSwitchListener(this);

		// register this as a switch listener for the compressor
		((GRTSwitch) cannonCompressor.getSensor("pressureSwitch"))
				.addSwitchListener(this);
	}

	// Actions

	/**
	 * if barrel ready Opens and closes solenoid timed by delay and sensor
	 * (which ever comes first)
	 */
	public void fire() {
		// make sure we're ready to fire.
		// just in case we have a full tank and dont notice
		if ((activeBarrel == LEFT_BARREL && !leftReady)
				|| (activeBarrel == RIGHT_BARREL && !rightReady)) {
			if (leftReady) {
				switchActiveBarrel();
				fire();
			} else if (rightReady) {
				switchActiveBarrel();
				fire();
			}
			return;
		}

		// open the valve
		getActuator((activeBarrel == LEFT_BARREL) ? "tankasol" : "tankbsol")
				.enqueueCommand(GRTSolenoid.ON);
		firing = true;
		// flag the barrel just fired as not ready;

		// timeout:
		long startTime = System.currentTimeMillis();
		while (firing
				&& System.currentTimeMillis() - startTime < TIMEOUT_LENGTH) {
			// block
			try {
				Thread.sleep(SLEEP_TIME);
			} catch (InterruptedException ie) {
				ie.printStackTrace();
			}
		}
		// close the valve
		getActuator((activeBarrel == LEFT_BARREL) ? "tankasol" : "tankbsol")
				.enqueueCommand(GRTSolenoid.OFF);
		if (activeBarrel == LEFT_BARREL) {
			leftReady = false;
			if (rightReady) {
				switchActiveBarrel();
			}
		} else if (activeBarrel == RIGHT_BARREL) {
			rightReady = false;
			if (leftReady) {
				switchActiveBarrel();
			}
		}
	}

	public void switchPressed(GRTSwitch source) { // Compressors are ready
		// which tank were we changing when we left off?
		// Which tank was INACTIVE?
		// that one is now FULL.
		if (source.getId().equals("pressureSwitch")) {
			if (inactiveBarrel == LEFT_BARREL) {
				leftReady = true;
				switchActiveBarrel();
				// put the two way valve in the right place
			} else if (inactiveBarrel == RIGHT_BARREL) {
				rightReady = true;
				switchActiveBarrel();
				// put the two way valve in the right place
			}
		} else if (source.getId().equals("fireSwitch")) {
			firing = false;
		}

	}

	// Overrides
	public void fireLeft() {
		this.tankASolenoid.enqueueCommand(GRTSolenoid.ON);
	}

	public void fireRight() {
		this.tankBSolenoid.enqueueCommand(GRTSolenoid.ON);
	}

	public void closeLeft() {
		this.tankASolenoid.enqueueCommand(GRTSolenoid.OFF);
	}

	public void closeRight() {
		this.tankASolenoid.enqueueCommand(GRTSolenoid.OFF);
	}

	public void switchActiveBarrel() {
		activeBarrel = (activeBarrel == LEFT_BARREL ? RIGHT_BARREL
				: LEFT_BARREL);
		inactiveBarrel = (activeBarrel == LEFT_BARREL ? RIGHT_BARREL
				: LEFT_BARREL);
		if (inactiveBarrel == RIGHT_BARREL) {
			tankSelectorSolenoid.enqueueCommand(GRTTwoWaySolenoid.FORWARD);
		} else if (inactiveBarrel == LEFT_BARREL) {
			tankSelectorSolenoid.enqueueCommand(GRTTwoWaySolenoid.REVERSE);
		}
	}

	public void switchReleased(GRTSwitch source) {
	}

	public boolean isFiring() {
		return firing;
	}

	public boolean isLeftReady() {
		return leftReady;
	}

	public boolean isRightReady() {
		return rightReady;
	}

	public int getActiveBarrel() {
		return activeBarrel;
	}

	public int getInactiveBarrel() {
		return inactiveBarrel;
	}

	public boolean readyToFire() {
		return leftReady || rightReady;
	}

}
